#include <iostream>

#include <log.h>

enum A {
    aA = 0,
    bA = 1,
    cA = 2,
    dA = 3,
    eA = 4,
    fA = 5,
};

enum class B : int {
    aB = 0,
    bB = 1,
    cB = 2,
    dB = 3,
    eB = 4,
    fB = 5,
    max,
    start = aB,
    end = max,
};

B& operator++(B &b)
{
    b = static_cast<B>(static_cast<int>(b) + 1);
    return b;
}

B operator++(B &b, int)
{
    auto ret = b;
    b = static_cast<B>(static_cast<int>(b) + 1);
    return ret;
}

enum C {
    aC = 0,
    bC = 1,
};

std::ostream &operator <<(std::ostream &os, const enum B &b)
{
    os << "static_cast<int>(" << static_cast<int>(b) << ")" << std::endl;
    return os;
}

std::ostream &operator <<(std::ostream &os, const enum C &c)
{
    os << "(" << static_cast<int>(c) << ")";
    return os;
}

B operator |(const B &a, const B &b)
{
    return static_cast<enum B>(static_cast<int32_t>(a) + static_cast<int32_t>(b));
}

int main()
{
    auto num = B::aB | B::bB;
    VALUE_LOGGER(num);

    OUTER_LOGGER() << "C语言风格的枚举定义，enum可加可不加";
    CODE_LOGGER(A a = aA;);
    CODE_LOGGER(enum A b = aA;);

    OUTER_LOGGER() << "enum枚举值属于全局空间，因此可以局部覆盖";
    CODE_LOGGER(enum A aA = ::aA;);

    OUTER_LOGGER() << "enum可隐式转化为int";
    CODE_LOGGER(int c = a;);

    OUTER_LOGGER() << "int不可隐式转化为enum，可以用static_cast";
    CODE_LOGGER(enum A d = static_cast<enum A>(0););

    OUTER_LOGGER() << "enum 可直接输出，视为int";
    CODE_LOGGER(std::cout << a << b << aA << c << d << std::endl;);

    OUTER_LOGGER() << "但是enum仍可以重载，自定义输出";
    CODE_LOGGER(enum C j = aC;);
    CODE_LOGGER(std::cout << j << std::endl;);

    HORIZONTAL_LINE();

    OUTER_LOGGER() << "C++风格的强枚举类定义是enum class";

    OUTER_LOGGER() << "enum class变量定义，enum可加可不加";
    CODE_LOGGER(B e = B::aB);
    CODE_LOGGER(enum B f = B::bB);

    OUTER_LOGGER() << "enum class枚举值属于类名空间";
    OUTER_LOGGER() << "enum class不可隐式转化为int";
    CODE_LOGGER(int g = static_cast<int>(e));

    OUTER_LOGGER() << "int不可隐式转化为enum class，可以用static_cast";
    CODE_LOGGER(enum B h = static_cast<enum B>(0););
    CODE_LOGGER(enum B i = static_cast<enum B>(6););

    OUTER_LOGGER() << "不可直接输出，必须实现ostream才能输出";
    CODE_LOGGER(std::cout << e << f << g << h << i << std::endl;);

    VALUE_LOGGER(B::start); // 0
    VALUE_LOGGER(B::end); // 5
    VALUE_LOGGER(B::max); // 6

    for (auto i = B::start; i < B::max; i++) {
        VALUE_LOGGER(i);
    } // 0 ~ 5

    for (auto i = B::start; i < B::max; ++i) {
        VALUE_LOGGER(i);
    } // 0 ~ 5
    return 0;
}
